package com.bsj.power.pls.config.net.netty.protocol;

import cn.hutool.core.util.HexUtil;
import com.alibaba.fastjson.JSON;
import com.bsj.power.common.def.vo.pls.uwb.UWBExtendVO;
import com.bsj.power.common.util.Conv;
import com.bsj.power.common.util.ConvUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author yinhao
 * @version 1.0
 * @description 服务端数据下行
 * @date 2024/9/25
 */
@Slf4j
public class UWBAck {

    /**
     * 终端参数设置 *C:10 上传间隔为10s（目前只有上传间隔一个参数）
     * 例：  *P:YTGPS*C:10*G:0
     *      *P:标识，YTGPS固定不变；
     *      *C:上传间隔，单位：秒
     *      *G:=0关闭北斗定位功能，=1打开北斗定位功能
     * @param content
     * @return
     */
    public static byte[] paramSet(byte[] content) {
        int len = content.length + 5;
        //总数据
        byte[] data = new byte[len];
        int offset = 0;
        //包头
        data[offset++] = 0x24;
        //指令类型
        data[offset++] = (byte) 0xEF;
        //长度
        data[offset++] = (byte) (content.length + 2);
        //内容
        System.arraycopy(content, 0, data, offset, content.length);
        offset += content.length;
        byte xor = Conv.CheckXor(data, 0, len - 2);
        //异或校验
        data[offset++] = xor;
        data[offset++] = (byte) 0xff;
        return data;
    }

    /**
     * 调度下发
     * @param content TTS语音播报内容
     * 字符需要转成GBK格式，"你好,世界".getBytes("GBK")
     * @return
     */
    public static byte[] dispatchIssued(byte[] content) {
        int len = content.length + 5;
        //总数据
        byte[] data = new byte[len];
        int offset = 0;
        //包头
        data[offset++] = 0x24;
        //指令类型
        data[offset++] = (byte) 0xED;
        //长度
        data[offset++] = (byte) (content.length + 2);
        //内容
        System.arraycopy(content, 0, data, offset, content.length);
        offset += content.length;
        byte xor = Conv.CheckXor(data, 0, len - 2);
        //异或校验
        data[offset++] = xor;
        data[offset++] = (byte) 0xff;
        return data;
    }

    /**
     * 下发声光报警指令
     * 报警内容 ：03 01
     * 第一个字节  03：声光报警次数（范围3—10）
     * 第二个字节  01: 声光报警
     *           02: 声音报警
     *           03: 光报警
     * @param content
     * @return
     */
    public static byte[] alarmCmd(byte[] content) {
        int len = content.length + 5;
        //总数据
        byte[] data = new byte[len];
        int offset = 0;
        //包头
        data[offset++] = 0x24;
        //指令类型
        data[offset++] = (byte) 0xEC;
        //长度
        data[offset++] = (byte) (content.length + 2);
        //内容
        System.arraycopy(content, 0, data, offset, content.length);
        offset += content.length;
        byte xor = Conv.CheckXor(data, 0, len - 2);
        //异或校验
        data[offset++] = xor;
        data[offset++] = (byte) 0xff;
        return data;
    }

    /**
     * RTK数据下发
     * @param content 内容
     * @param now 当前包
     * @param total 总包数
     * @param num 包序号
     * @return
     */
    public static byte[] rtkSend(byte[] content, int now, int total, int num) {
        //需要将数据分成多少包,最多一包57个字节
        int len = content.length + 3 + 5;
        //总数据
        byte[] data = new byte[len];
        int offset = 0;
        //包头
        data[offset++] = 0x24;
        //指令类型
        data[offset++] = (byte) 0xEA;
        //长度
        data[offset++] = (byte) (content.length + 3 + 2);
        //包序
        data[offset++] = (byte) num;
        //总包数
        data[offset++] = (byte) total;
        //当前包序
        data[offset++] = (byte) now;
        //内容
        System.arraycopy(content, 0, data, offset, content.length);
        offset += content.length;
        byte xor = Conv.CheckXor(data, 0, len - 2);
        //异或校验
        data[offset++] = xor;
        data[offset++] = (byte) 0xff;
        return data;
    }

    /**
     * 解析经纬度状态以及报警信息
     * @param alarmByte
     */
    public static UWBExtendVO analysisAlarmInfo(byte[] alarmByte) {
        int len = alarmByte.length;
        if (len < 5) {
            //数据长度不对
            return null;
        }
        int offset = 0;
        //头
        if (alarmByte[offset] != 0x24) {
            //头不对
            return null;
        }
        offset += 1;
        //指令码
        if (Byte.toUnsignedInt(alarmByte[offset]) != 0xE9) {
            //指令码不对
            return null;
        }
        offset += 1;
        //数据长度
        int dataLen = Byte.toUnsignedInt(alarmByte[offset]);
        offset += 1;
        if (dataLen + 3 != len) {
            //数据有误
            return null;
        }
        //数据体
        byte[] dataByte = new byte[dataLen - 3];
        System.arraycopy(alarmByte, offset, dataByte, 0, dataLen - 3);
        int dataOffset = 0;
        //报警标志
        int alarmState = Byte.toUnsignedInt(dataByte[dataOffset]);
        //SOS报警位 =1 SOS报警 =0正常
        int alarmBit0 = (alarmState & 0x01) != 0 ? 1 : 0;
        //低压报警，=1低压报警，=0正常
        int alarmBit1 = (alarmState & 0x02) != 0 ? 1 : 0;
        dataOffset += 1;
//        log.info("alarmBit0: {}, alarmBit1: {}", alarmBit0, alarmBit1);
        //状态
        int state = Byte.toUnsignedInt(dataByte[dataOffset]);
        //定位状态，=1定位，=0未定位
        int stateBit0 = (state & 0x01) != 0 ? 1 : 0;
        //上下班状态 =1上班， = 0下班
        int stateBit1 = (state & 0x02) != 0 ? 1 : 0;
        //=0关闭北斗定位功能，=1打开北斗定位功能
        int stateBit2 = (state & 0x04) != 0 ? 1 : 0;
        //0=普通定位  1=RTK定位
        int stateBit3 = (state & 0x08) != 0 ? 1 : 0;
        dataOffset += 1;
//        log.info("stateBit0: {}, stateBit1: {}, stateBit2: {}, stateBit3: {}",
//                stateBit0, stateBit1, stateBit2, stateBit3);
        //纬度
        long lat = ConvUtil.getIntNetOrder(dataByte, dataOffset);
        dataOffset += 4;
        //经度
        long lon = ConvUtil.getIntNetOrder(dataByte, dataOffset);
        dataOffset += 4;
//        log.info("lat: {}, lon:{}", lat, lon);
        //电池电量
        int power = Byte.toUnsignedInt(dataByte[dataOffset]);
        dataOffset += 1;
        //厂商ID
        int firmId = ConvUtil.getShortNetOrder(dataByte, dataOffset);
        dataOffset += 2;
//        log.info("power: {}, firmId: {}", power, firmId);
        //时间 6字节 BCD码，格式：yymmddhhmmss，如：240909121010
        dataOffset += 6;
        //校验位 2字节 厂商ID和时间字段的累加和，与当前校验位相等时，平台允许显示，否则不予显示位置
        dataOffset += 2;
        UWBExtendVO extendVO = UWBExtendVO.builder()
                .sosAlarm(alarmBit0).lowPressureAlarm(alarmBit1).posState(stateBit0)
                .workState(stateBit1).bdPosState(stateBit2).rtkPosState(stateBit3).lat(lat).lon(lon)
                .power(power).firmId(firmId)
                .build();
        return extendVO;
    }

    /**
     * 解析RTK包上报结果
     * @param rtkAckByte
     * @return
     */
    public static Map<Integer, List<Integer>> rtkAck(byte[] rtkAckByte) {
        int len = rtkAckByte.length;
        if (len < 10) {
            //数据长度不对
            return null;
        }
        int offset = 0;
        //头
        if (rtkAckByte[offset] != 0x24) {
            //头不对
            return null;
        }
        offset += 1;
        //指令码
        if (Byte.toUnsignedInt(rtkAckByte[offset]) != 0xEA) {
            //指令码不对
            return null;
        }
        offset += 1;
        List<Integer> page = new ArrayList<>();
        //数据长度
        int dataLen = Byte.toUnsignedInt(rtkAckByte[offset]);
        offset += 1;
        //包序
        int num = Byte.toUnsignedInt(rtkAckByte[offset]);
        offset += 1;
        //结果1
        int one = Byte.toUnsignedInt(rtkAckByte[offset]);
        offset += 1;
        if (one != 0) {
            page.add(one);
        }
        //结果2
        int two = Byte.toUnsignedInt(rtkAckByte[offset]);
        offset += 1;
        if (two != 0) {
            page.add(two);
        }
        //结果3
        int three = Byte.toUnsignedInt(rtkAckByte[offset]);
        offset += 1;
        if (three != 0) {
            page.add(three);
        }
        //结果4
        int four = Byte.toUnsignedInt(rtkAckByte[offset]);
        offset += 1;
        if (four != 0) {
            page.add(four);
        }
        if (!page.isEmpty()) {
            return Map.of(num, page);
        } else {
            return null;
        }
    }

    public static void main(String[] args) throws Exception{
        //终端参数设置
        String set = "*P:YTGPS*C:30";
        byte[] setBytes = paramSet(set.getBytes("GBK"));
        System.out.println(HexUtil.encodeHexStr(setBytes, false));
        //TTS 语音播报
        String s = "你好,世界";
        byte[] bytes = dispatchIssued(s.getBytes("GBK"));
        System.out.println(HexUtil.encodeHexStr(bytes, false));
        //声光报警
        byte[] alByte = alarmCmd(new byte[]{0x03, 0x01});
        System.out.println(HexUtil.encodeHexStr(alByte, false));
        //报警信息解析
        String alarmStr = "24e9170201015a29b806cbf6380003e9241009114520019f2d0a";
        byte[] alarmByte = HexUtil.decodeHex(alarmStr);
        UWBExtendVO extendVO = analysisAlarmInfo(alarmByte);
        System.out.println(JSON.toJSONString(extendVO));
    }
}
